package api.action;

import api.model.ApiColumn;
import api.model.ApiTable;
import api.service.ApiTableService;
import m.common.action.ActionMeta;
import m.common.action.RequestMeta;
import m.common.action.VuePageResult;
import m.common.action.VueResult;
import m.common.model.Model;
import m.common.model.TableMeta;
import m.common.model.config.ModelConfig;
import m.common.model.util.*;
import m.html.VueCollectResult;
import m.html.VueListResult;
import m.html.collect.CollectColumn;
import m.html.collect.CollectColumnType;
import m.html.element.attr.Align;
import m.html.element.attr.ButtonType;
import m.html.element.other.DisplayItem;
import m.html.element.other.Param;
import m.html.list.*;
import m.system.cache.CacheUtil;
import m.system.db.TransactionManager;
import m.system.exception.MException;
import m.system.util.*;
import manage.action.ManageAction;
import manage.model.AdminLogin;
import manage.util.DictionaryUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@ActionMeta(name="api/apiTable")
public class ApiTableAction extends ManageAction {
    private ApiTable model;

    /**
     * 列表页面 根据tableOid展示数据
     *
     *  Exception
     */
    public VueResult toTablePage() throws Exception {
        boolean isExport="Y".equals(getParamsValue("export"));//导出模板
        verifyMenu("A2101");
        verifyAdminOperPower("manage_api_power");
        AdminLogin admin=getSessionAdmin();
        String tableOid=getParamsValue("tableOid");
        ApiTable apiTable=CacheUtil.get(ApiTable.class,tableOid);
        List<ApiColumn> cols=CacheUtil.getList(ApiColumn.class,apiTable.getOid());
        FromQueryList from=FromQueryList.from("a",apiTable.getOid());
        if(isExport) from.addCondition("1=2");//导出模板，不查数据
        VueCollectResult result=getVueCollectResult(apiTable.getDescription(), from, "action/api/apiTable/toTablePage");
        result.setFunction(true,false);
        for(int i=0;i<cols.size();i++){
            ApiColumn col=cols.get(i);
            if("Y".equals(col.getIsinit())){
                String fk="f"+i;
                String field="#{a."+col.getName()+"} "+fk;
                String text=col.getDescription().split("\\|")[0];
                if(isExport){
                    if(!StringUtil.isSpace(col.getDictType())){
                        text+="\r\n取值："+ ArrayUtil.connection(DictionaryUtil.getTitle(col.getDictType()).values().toArray(new String[0]),",");
                    }else if(!StringUtil.isSpace(col.getDictOption())){
                        text+="\r\n取值："+ ArrayUtil.connection(DisplayItem.titles(DisplayItem.to(col.getDictOption().split(":|,"))),",");
                    }else if(ObjectUtil.notEmptyOid(col.getModelTable())){
                        text+="\r\n取值："+col.getModelTable().getDescription()+"（"+col.getModelTable().getName()+"）-主键";
                    }
                }
                CollectColumn cc;
                if("DATE".equals(col.getType())){
                    cc=collectDateTimeColumn(text,field,140,true).setDateFormat(DateUtil.YYYY_MM_DD_HH_MM_SS);
                }else if("INT".equals(col.getType())){
                    cc=collectIntegerColumn(text,field,100,true);
                }else if("DOUBLE".equals(col.getType())){
                    cc=collectNumberColumn(text,field,120,true);
                }else{
                    int width=80+col.getLength();
                    if(width>350) width=350;
                    cc=collectTextColumn(text,field,width,true);
                }
                if(!StringUtil.isSpace(col.getDictType())){
                    cc.setDictType(col.getDictType());
                }else if(!StringUtil.isSpace(col.getDictOption())){
                    cc.setDisItems(DisplayItem.to(col.getDictOption().split(":|,")));
                }
                if(!StringUtil.isSpace(col.getModelClass())){
                    cc.setType(CollectColumnType.LINK)
                    .setLinkEvent(
                        new ListEvent("action/api/apiTable/toViewModel", EventType.MODAL,600)
                            .addParam(Param.value("modelClass",col.getModelClass()))
                            .addParam(fk+"1",Param.field("oid","#{a."+col.getName()+"}"))
                    );
                }else if(ObjectUtil.notEmptyOid(col.getModelTable())) {
                    cc.setType(CollectColumnType.LINK)
                    .setLinkEvent(
                        new ListEvent("action/api/apiTable/toViewTable", EventType.MODAL,600)
                            .addParam(Param.value("tableOid",col.getModelTable().getOid()))
                            .addParam(fk+"1",Param.field("oid","#{a."+col.getName()+"}"))
                    );
                }
                getParams().putIfAbsent("view_" + fk, "true");
                if(isExport) cc.setCount(ListCount.NONE);
                result.addCol(cc.setSort(true));
            }
        }
        if("N".equals(apiTable.getSource())){
            result.addButton(ListButton.importExcel("导入",ButtonType.PRIMARY,"action/api/apiTable")
                .addQueryParam(Param.value("importParam",apiTable.getOid())));
        }
        return result;
    }

    @Override
    protected JSONMessage processImportSetting(String importParam) {
        ApiTable apiTable=CacheUtil.get(ApiTable.class,importParam);
        return new JSONMessage()
            .push("tempName",apiTable.getDescription())
            .push("tempPath","action/api/apiTable/exportExcel?method=toTablePage&params[export]=Y&params[tableOid]="+apiTable.getOid())
            .push("alertMessage","导入数据根据主键控制唯一，导入重复的主键则覆盖；主键列为空则自动生成唯一主键。");
    }
    @Override
    protected String processImportData(List<String[]> data, String importParam) throws Exception {
        boolean power=hasAdminOperPower("manage_api_power");
        if(!power) throw new MException(this.getClass(),"当前账号无权导入数据");
        ApiTable apiTable=CacheUtil.get(ApiTable.class,importParam);
        List<ApiColumn> cols=CacheUtil.getList(ApiColumn.class,apiTable.getOid());
        ApiTableService service=getService(ApiTableService.class);
        String msg;
        TransactionManager tm=new TransactionManager();
        try{
            tm.begin();
            int n=0,m=0;
            StringBuffer error=new StringBuffer();
            for(int i=0;i<data.size();i++){
                String[] obj=data.get(i);
                obj=parseRowData(obj,cols.size());
                int row=i+1;
                StringBuffer e=new StringBuffer();
                Map<String,Object> d=new HashMap<>();
                for(int j=0;j<cols.size();j++){
                    ApiColumn ac=cols.get(j);
                    String name=ac.getDescription().split("\\|")[0];
                    if("DOUBLE".equals(ac.getType())){
                        d.put(ac.getName(),parseDouble(obj[j],row,name,e));
                    }else if("INT".equals(ac.getType())){
                        d.put(ac.getName(),parseInteger(obj[j],row,name,e));
                    }else if("DATE".equals(ac.getType())){
                        d.put(ac.getName(),parseDate(obj[j],row,name,e));
                    }else{
                        d.put(ac.getName(),parseString(obj[j]));
                    }
                    if(null==d.get(ac.getName())&&"Y".equals(ac.getNotnull())&&!"oid".equals(ac.getName())){
                        e.append("\r\n第").append(row).append("行").append(name).append("不能为空");
                    }
                    if("STRING".equals(ac.getType())&&StringUtil.notSpace((String)d.get(ac.getName()))){
                        String v=(String)d.get(ac.getName());
                        if(StringUtil.notSpace(ac.getDictType())){
                            if(null==DictionaryUtil.getValue(ac.getDictType(), v))
                                e.append("\r\n第").append(row).append("行").append(name).append("取值错误");
                        }else if(StringUtil.notSpace(ac.getDictOption())){
                            List<DisplayItem> ls=DisplayItem.to(ac.getDictOption().split(":|,"));
                            if(null==DisplayItem.getValue(ls,v))
                                e.append("\r\n第").append(row).append("行").append(name).append("取值错误");
                        }else if(ac.getLength()<v.length()){
                            e.append("\r\n第").append(row).append("行").append(name).append("长度不能超过").append(ac.getLength());
                        }
                    }else if(("MODEL".equals(ac.getType())||"TABLE".equals(ac.getType()))
                            &&StringUtil.notSpace((String)d.get(ac.getName()))){
                        String v=(String)d.get(ac.getName());
                        SystemUtil.println(ac);
                        List<Map<String,Object>> ml= TableQueryList.getList(ac.getModelTable().getOid(),new String[]{"oid"},null,
                                QueryCondition.eq("oid",v));
                        if(ml.size()==0){
                            e.append("\r\n第").append(row).append("行").append(name).append("取值错误");
                        }
                    }
                }
                if(e.length()>0){
                    error.append(e);
                }else {
                    boolean b=service.saveModel(apiTable.getOid(), d);
                    if(!b) m++;
                }
                n++;
            }
            if(error.length()>0){
                throw new MException(this.getClass(),error.toString());
            }
            msg="成功导入了"+n+"条！"+(m>0?("其中"+m+"条是更新"):"");
            tm.commit();
        }catch (Exception e){
            tm.rollback();
            throw e;
        }
        return msg;
    }


    @RequestMeta(params = {"modelClass","oid"})
    public VueResult toViewModel(String modelClass,String oid) throws Exception {
        verifyAdminOperPower("manage_api_power");
        Model mc = ClassUtil.newInstance(modelClass);
        mc.setOid(oid);
        return new VuePageResult("page/base/api/viewModel.js")
            .addParam("json", ModelQueryUtil.getModel(mc));
    }
    @RequestMeta(params = {"tableOid","oid"})
    public VueResult toViewTable(String tableOid,String oid) throws Exception {
        verifyAdminOperPower("manage_api_power");
        List<Map<String, Object>> ls = TableQueryList.getList(tableOid, new String[]{"*"}, null,
            QueryCondition.eq("oid", oid));
        return new VuePageResult("page/base/api/viewModel.js")
            .addParam("json", ls.size()>0?ls.get(0):new JSONMessage());
    }

    public JSONMessage doSave(){
        JSONMessage result=new JSONMessage();
        try {
            verifyAdminOperPower("manage_api_power");
            String msg=getService(ApiTableService.class).save(model);
            result.push("model", model);
            fillJSONResult(result,true,msg);
        } catch (Exception e) {
            fillJSONResult(result,false,e);
        }
        return result;
    }
    public JSONMessage doDelete(){
        JSONMessage result=new JSONMessage();
        try {
            verifyAdminOperPower("manage_api_power");
            String msg=getService(ApiTableService.class).delete(model);
            fillJSONResult(result,true,msg);
        } catch (Exception e) {
            fillJSONResult(result,false,e);
        }
        return result;
    }
    public JSONMessage doInit(){
        JSONMessage result=new JSONMessage();
        try {
            verifyAdminOperPower("manage_api_power");
            String msg=getService(ApiTableService.class).init(model);
            try{
                CacheUtil.clear(ApiColumn.class);
                CacheUtil.clear(ApiTable.class);
            }catch (Exception ignored){}
            fillJSONResult(result,true,msg);
        } catch (Exception e) {
            fillJSONResult(result,false,e);
        }
        return result;
    }

    public VueResult toEdit() throws Exception {
        verifyMenu("A2101");
        verifyAdminOperPower("manage_api_power");
        List<JSONMessage> sourceList= new ArrayList<>();
        if(null!=model&&!StringUtil.isSpace(model.getOid())){
            model= ModelQueryList.getModel(model,"*");
        }else {
            model=new ApiTable();
            model.setSource("N");
            List<Class<? extends Model>> classList=ModelConfig.getTableList();
            for(Class<? extends Model> clazz : classList){
                TableMeta tm=ModelConfig.getTableMeta(clazz);
                JSONMessage data=new JSONMessage();
                data.push("key", clazz.getName());
                data.push("value", clazz.getName());
                boolean isSys= clazz.getName().contains("manage.model") || clazz.getName().contains("flow.model")
                    || clazz.getName().contains("api.model");
                data.push("label", (isSys?"[系统] ":"")+tm.description()+" "+tm.name());
                sourceList.add(data);
            }
        }
        return new VuePageResult("page/base/api/editApiTable.js")
            .addParam("model",model)
            .addParam("sourceList",sourceList);
    }
    public VueResult apiTableList() throws Exception{
        verifyMenu("A2101");
        boolean power=hasAdminOperPower("manage_api_power");
        VueListResult result=getVueListResult("数据表列表", ApiTable.class,"action/api/apiTable/apiTableList");
        result.setSubTitle("添加或者编辑数据表信息。");
        result.addCol(toIndexColumn());
        result.addCol(toTextColumn("标识", "name",true));
        result.addCol(toTextColumn("描述", "description",200,true));
        result.addCol(toTextColumn("来源", "source",true).addDisItem("Y","表","N","自建"));
        result.addCol(toTextColumn("来源表", "sourceDesc",true));
        result.addCol(toTextColumn("生成", "isinit",true).addDisItem("Y","是","N","否"));
        if(power) result.addCol(toSpaceColumn("操作",200,
            ListButton.modal("修改", ButtonType.PRIMARY,"action/api/apiTable/toEdit",900, SuccessMethod.REFRESH)
                .addParam("model.oid","oid"),
            ListElement.test("record.source!='Y'",
                ListButton.ajax("生成", ButtonType.SUCCESS,"action/api/apiTable/doInit", SuccessMethod.REFRESH)
                    .addParam("model.oid","oid").setConfirm("生成表和字段，可重复操作，生成后字段不可修改。")
            ),
            ListElement.test("record.isinit!='Y'",
                ListButton.ajax("删除", ButtonType.WARN,"action/api/apiTable/doDelete", SuccessMethod.REFRESH)
                    .addParam("model.oid","oid").setConfirm("确定要删除该自建表吗?")
            ),
            ListElement.elseOther(
                ListButton.page("查询", ButtonType.LINK,"action/api/apiTable/toTablePage", SuccessMethod.REFRESH)
                    .addParam("params[tableOid]","oid")
            )
        ).setFixed(Align.RIGHT));
        if(power) result.addButton(
            ListButton.modal("新增",ButtonType.PRIMARY,"action/api/apiTable/toEdit",900,SuccessMethod.REFRESH)
        );
        return result;
    }

    public ApiTable getModel() {
        return model;
    }

    public void setModel(ApiTable model) {
        this.model = model;
    }

}
